package com.hyzx.qbasic.admin.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.hyzx.qbasic.admin.domain.repository.IDbQueryRepository;
import com.hyzx.qbasic.admin.domain.service.IOperationsService;
import com.hyzx.qbasic.admin.domain.service.IPoiService;
import com.hyzx.qbasic.admin.model.vo.req.admin.DbQueryReq;
import com.hyzx.qbasic.common.util.HttpClientUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by 黄江华 on 2017/10/31
 */

@Service
public class OperationsServiceImpl implements IOperationsService {
    private static final Logger logger = LoggerFactory.getLogger(OperationsServiceImpl.class);

    private static final String ACTUATOR_HEALTH_ENDPOINT = "/actuator/health";
    private static final String ACTUATOR_METRICS_ENDPOINT = "/actuator/metrics";

    @Autowired
    IDbQueryRepository dbQueryRepository;

    @Autowired
    private IPoiService poiService;

    @Override
    public PageInfo<Map<String, Object>> dbQuery(DbQueryReq req) {
        try {
            return dbQueryRepository.query(req.getPageNum(), req.getPageSize(), req.getSql());
        } catch (Exception ex) {
            logger.error(String.format("数据库查询异常，SQL：%s", req.getSql()), ex);
        }

        return null;
    }

    @Override
    public void dbExport(String sql, HttpServletResponse response) {
        if (StringUtils.isBlank(sql)) {
            return;
        }

        //获取第一页数据列表
        DbQueryReq req = new DbQueryReq();
        req.setSql(sql);
        req.setPageNum(1);
        req.setPageSize(100);
        PageInfo<Map<String, Object>> pageInfo = this.dbQuery(req);
        if (pageInfo == null || pageInfo.getSize() == 0) {
            return;
        }

        //导出文件名
        String fileName = "数据导出";
        //导出到第一个工作表
        int sheetIndex = 0;
        //创建Excel工作簿对象
        HSSFWorkbook workbook = new HSSFWorkbook();
        workbook.createSheet();

        // 第一个工作表模板每列数据字段名
        List<String> cols = new ArrayList<>();
        pageInfo.getList().get(0).forEach((key, Value) -> cols.add(key));

        //导出第一页数据
        List<Map<String, Object>> dataList = pageInfo.getList();
        int totalPages = pageInfo.getPages();
        poiService.exportExcelTitleRow(workbook, sheetIndex, cols, 0);
        poiService.exportMapToExcel(workbook, sheetIndex, cols, 1, dataList);

        //导出第二至最后页数据
        for (int i = 2; i <= totalPages; i++) {
            req.setPageNum(i);
            pageInfo = this.dbQuery(req);
            dataList = pageInfo.getList();

            int offset = pageInfo.getStartRow();
            poiService.exportMapToExcel(workbook, sheetIndex, cols, offset, dataList);
        }

        //输出响应
        poiService.exportExcelToResponse(workbook, fileName, response);
    }

    @Override
    public Map<String, Object> getAppMonitorInfo(String domain) {
        String healthInfoUrl = domain + ACTUATOR_HEALTH_ENDPOINT;
        String metricsInfoUrl = domain + ACTUATOR_METRICS_ENDPOINT;

        Map<String, Object> monitorInfo = new HashMap<>();
        try {
            String healthInfoStr = HttpClientUtil.requestGet(healthInfoUrl, null);
            JSONObject healthInfo = JSON.parseObject(healthInfoStr);
            JSONObject healthDetailInfo = healthInfo.getJSONObject("details");

            String serverStatus = healthInfo.getString("status");
            monitorInfo.put("status", "UP".equalsIgnoreCase(serverStatus) ? "正常" : "异常");

            JSONObject diskSpaceInfo = healthDetailInfo.getJSONObject("diskSpace");
            JSONObject diskSpaceDetailInfo = diskSpaceInfo.getJSONObject("details");
            double diskSpaceTotal = diskSpaceDetailInfo.getDouble("total") / (1024 * 1024 * 1024);
            double diskSpaceFree = diskSpaceDetailInfo.getDouble("free") / (1024 * 1024 * 1024);
            double diskSpaceUsage = diskSpaceTotal - diskSpaceFree;
            double diskSpaceUsageRate = diskSpaceUsage / diskSpaceTotal * 100;
            monitorInfo.put("diskSpaceTotal", String.format("%.2fGB", diskSpaceTotal));
            monitorInfo.put("diskSpaceFree", String.format("%.2fGB", diskSpaceFree));
            monitorInfo.put("diskSpaceUsage", String.format("%.2fGB", diskSpaceUsage));
            monitorInfo.put("diskSpaceUsageRate", String.format("%.2f", diskSpaceUsageRate));

            String dbStatus = healthDetailInfo.getJSONObject("db").getString("status");
            monitorInfo.put("dbStatus", "UP".equalsIgnoreCase(dbStatus) ? "正常" : "异常");

            String heapTotalUrl = metricsInfoUrl + "/jvm.memory.max?tag=area:heap";
            String heapTotalInfoStr = HttpClientUtil.requestGet(heapTotalUrl, null);
            JSONObject heapTotalInfo = JSON.parseObject(heapTotalInfoStr);

            String heapUsedUrl = metricsInfoUrl + "/jvm.memory.used?tag=area:heap";
            String heapUsedInfoStr = HttpClientUtil.requestGet(heapUsedUrl, null);
            JSONObject heapUsedInfo = JSON.parseObject(heapUsedInfoStr);

            long jvmHeapTotal = heapTotalInfo.getJSONArray("measurements")
                    .getJSONObject(0).getLong("value") / (1024 * 1024);
            long jvmHeapUsage = heapUsedInfo.getJSONArray("measurements")
                    .getJSONObject(0).getLong("value") / (1024 * 1024);
            long jvmHeapFree = jvmHeapTotal - jvmHeapUsage;
            double jvmHeapUsageRate = (double) jvmHeapUsage / jvmHeapTotal * 100;
            monitorInfo.put("jvmHeapTotal", String.format("%dMB", jvmHeapTotal));
            monitorInfo.put("jvmHeapFree", String.format("%dMB", jvmHeapFree));
            monitorInfo.put("jvmHeapUsage", String.format("%dMB", jvmHeapUsage));
            monitorInfo.put("jvmHeapUsageRate", String.format("%.2f", jvmHeapUsageRate));

            String uptimeUrl = metricsInfoUrl + "/process.uptime";
            String uptimeInfoStr = HttpClientUtil.requestGet(uptimeUrl, null);
            JSONObject uptimeInfo = JSON.parseObject(uptimeInfoStr);

            long jvmUptime = uptimeInfo.getJSONArray("measurements")
                    .getJSONObject(0).getLong("value") / 60;
            monitorInfo.put("jvmUptime", String.format("%d分钟", jvmUptime));

        } catch (Exception ex) {
            logger.error("获取actuator监控节点数据异常", ex);
        }

        return monitorInfo;
    }
}
